#pragma once
#include "gtest/gtest.h"

#include "TestData/model/OneBeam.hpp"
#include "TestData/model/Link_TwoELe.hpp"
#include "TestData/model/Desk_RBe2Surface.hpp"
#include "TestData/model/Desk_Rbar1feet.hpp"
#include "../DOFHandler.h"

using SG::DataStructure::Common::Id;
using SG::DataStructure::FEM::DOFTypes;
using SG::DataStructure::FEM::DOFDirections;
using SG::DataStructure::FEM::DofSet;
using SG::DataStructure::FEM::Field_Types;
using SG::FEMSolver::DOFHandler;
SG_NAMESPACE_OPEN
namespace FEMSolver
{
TEST (DOFHandlerTest, FindNodeIndex1)
{
    // Input data
    std::vector<Id> nodeIds {1, 2, 5, 8, 10};
    std::vector<std::size_t> indexes {0, 1, 2, 3, 4};
    // Test data
    DOFHandler handler(nodeIds, Field_Types::FIELD_Elastic, indexes);
    auto indexTest = handler.FindNodeIndex(10);
    //Target data
    const int indexTarget{4};
    //Check
    ASSERT_TRUE (indexTarget == indexTest);
}

TEST (DOFHandlerTest, MarkDofTypeOneBeamNoConstrainCase)
{
    // Input
    OneBeamNoConstrain model;
    auto dbServiceFactory = model.GetModel ();

    // Test data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTest;
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes {0, 1, 2};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Elastic, indexes);
    Subcase subcase;
    subcase.AddParameter({"SPC","1"});

    dofhandler.MarkDOFType (dbServiceFactory, subcase, DOFFlagTest);

    // Target data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTarget(18);
    for (std::size_t index = 0; index < 12; ++index)
    {
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Free;
    }
    for (std::size_t index = 12; index < 18; ++index)
    {
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Unknown;
    }

    const std::size_t activatedDofCountTarget = 12; 

    // Check
    ASSERT_TRUE (DOFFlagTarget == DOFFlagTest);
    ASSERT_TRUE (activatedDofCountTarget == dofhandler.ComputeSparseMatrixSize());
}

TEST (DOFHandlerTest, OneBeamCantileverCase)
{
    // Input
    OneBeamCantilever model;
    auto dbServiceFactory = model.GetModel ();

    // Test data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTest;
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes {0, 1, 2};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Elastic, indexes);
    Subcase subcase;
    subcase.AddParameter({"SPC","1"});
    // subcase.m_spc = 1;

    dofhandler.MarkDOFType (dbServiceFactory, subcase, DOFFlagTest);

    // Target data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTarget(18);
    for (std::size_t index = 0; index < 6; ++index)
    {
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Constraint;
    }
    for (std::size_t index = 6; index < 12; ++index)
    {
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Free;
    }
    for (std::size_t index = 12; index < 18; ++index)
    {
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Unknown;
    }

    const std::size_t activatedDofCountTarget = 6; 

    // Check
    ASSERT_TRUE (DOFFlagTarget == DOFFlagTest);
    ASSERT_TRUE (activatedDofCountTarget == dofhandler.ComputeSparseMatrixSize ());
    
    // DOF global index test
    std::vector<int> dofGlobalIndexesTest;
    dofhandler.Sort (DOFFlagTest);
    DofSet DOFs = getAllNodeDofs ();
    dofhandler.GetGlobalIndex (indexes, DOFs, dofGlobalIndexesTest);
    std::vector<int> dofGlobalIndexesTarget {6, 7, 8, 9, 10, 11,
                                             0, 1, 2, 3,  4,  5,
                                            -1, -1, -1, -1, -1, -1};

    ASSERT_TRUE (dofGlobalIndexesTest == dofGlobalIndexesTarget);

}

TEST (DOFHandlerTest, DofSortIncludeSPC)
{
    // Input
    OneBeamSimplySupported simSupportdBeam;
    auto dbServiceFactory = simSupportdBeam.GetModel ();

    // Test data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTest;
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes {0, 1, 2};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Elastic, indexes);
    Subcase subcase;
    // subcase.m_spc = 1;
    subcase.AddParameter({"SPC","1"});

    dofhandler.MarkDOFType (dbServiceFactory, subcase, DOFFlagTest);

    // Target data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTarget(18);
    // Node 1
    DOFFlagTarget[0] = DOFTypes::DOFTYPE_Constraint;
    DOFFlagTarget[1] = DOFTypes::DOFTYPE_Constraint;
    DOFFlagTarget[2] = DOFTypes::DOFTYPE_Constraint;
    DOFFlagTarget[3] = DOFTypes::DOFTYPE_Free;
    DOFFlagTarget[4] = DOFTypes::DOFTYPE_Free;
    DOFFlagTarget[5] = DOFTypes::DOFTYPE_Free;
    // Node 2
    DOFFlagTarget[6] = DOFTypes::DOFTYPE_Constraint;
    DOFFlagTarget[7] = DOFTypes::DOFTYPE_Constraint;
    DOFFlagTarget[8] = DOFTypes::DOFTYPE_Constraint;
    DOFFlagTarget[9] = DOFTypes::DOFTYPE_Free;
    DOFFlagTarget[10] = DOFTypes::DOFTYPE_Free;
    DOFFlagTarget[11] = DOFTypes::DOFTYPE_Free;
    // Direction node
    for (std::size_t index = 12; index < 18; ++index)
    {
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Unknown;
    }

    const std::size_t activatedDofCountTarget = 6; 
    

    // Check
    ASSERT_TRUE (DOFFlagTarget == DOFFlagTest);
    ASSERT_TRUE (activatedDofCountTarget == dofhandler.ComputeSparseMatrixSize());

    // DOF global index test
    std::vector<int> dofGlobalIndexesTest;
    dofhandler.Sort (DOFFlagTest);
    DofSet DOFs = getAllNodeDofs ();
    dofhandler.GetGlobalIndex (indexes, DOFs, dofGlobalIndexesTest);
    std::vector<int> dofGlobalIndexesTarget {6,  7,  8, 0, 1, 2,
                                             9, 10, 11, 3, 4, 5,
                                            -1, -1, -1, -1, -1, -1};
    ASSERT_TRUE (dofGlobalIndexesTest == dofGlobalIndexesTarget);
}

TEST (DOFHandlerTest, TwoLinkTrussCase)
{
    // Input
    Link_TwoEle model;
    auto dbServiceFactory = model.GetModel ();

    // Test data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTest;
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes {0, 1, 2};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Elastic, indexes);
    Subcase subcase;
    // subcase.m_spc = 1;
    subcase.AddParameter({"SPC","1"});

    dofhandler.MarkDOFType (dbServiceFactory, subcase, DOFFlagTest);

    // Target data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTarget(18, DOFTypes::DOFTYPE_Unknown);
    
    for (std::size_t index = 0; index < 3; ++index)
    {
        // Node 1
        DOFFlagTarget[index] = DOFTypes::DOFTYPE_Constraint;
        // Node 2
        DOFFlagTarget[index+6] = DOFTypes::DOFTYPE_Constraint;
    }
    DOFFlagTarget[12] = DOFTypes::DOFTYPE_Free;
    DOFFlagTarget[13] = DOFTypes::DOFTYPE_Free;
    DOFFlagTarget[14] = DOFTypes::DOFTYPE_Constraint;

    const std::size_t activatedDofCountTarget = 2; 

    // Check
    ASSERT_TRUE (DOFFlagTarget == DOFFlagTest);
    ASSERT_TRUE (activatedDofCountTarget == dofhandler.ComputeSparseMatrixSize ());
    
    // DOF global index test
    std::vector<int> dofGlobalIndexesTest;
    dofhandler.Sort (DOFFlagTest);
    DofSet DOFs = getAllNodeDofs (); // 杆单元实际不需要查询旋转自由度，只是为了查询不应激活的自由度是否确实没有激活
    dofhandler.GetGlobalIndex (indexes, DOFs, dofGlobalIndexesTest);
    std::vector<int> dofGlobalIndexesTarget {2, 3, 4, -1, -1, -1,
                                             5, 6, 7, -1, -1, -1,
                                             0, 1, 8, -1, -1, -1};

    ASSERT_TRUE (dofGlobalIndexesTest == dofGlobalIndexesTarget);
}

TEST (DOFHandlerTest, IncludeRBAR1Case)
{
    // Input
    Desk_RBAR1Surface model;
    auto dbServiceFactory = model.GetModel ();

    // Test data
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    //std::cout << "nodeIds size " << nodeIds.size() << std::endl;
    // for(auto v:nodeIds)
    // {
    //     std::cout << v <<"  ";
    // }
    const std::vector<std::size_t> indexes {0, 1, 2, 3, 4, 5, 6, 7};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Elastic, indexes);
    Subcase subcase;
    subcase.AddParameter({"SPC","1"});
    // subcase.m_spc = 1;

    dofhandler.Compute (dbServiceFactory, subcase);
    //std::cout << "dofhandler.Compute fini \n";
    DofSet DOFs = getAllNodeDofs (); 
    std::vector<int> dofGlobalIndexesTest;
    dofhandler.GetGlobalIndex (indexes, DOFs, _OUT dofGlobalIndexesTest);

    // Target data
    const std::vector<int> dofGlobalIdTarget
    {
        33, 34, 35, 0, 1, 2,
        3,   4, 36, 5, 6, 7,
        37, 38,  8,  9, 10, 11,
        12, 13, 14, 15, 16, 17,
        18, 19, 20, 21, 22, 23,
        39, 40, 41, 24, 25, 26,
        42, 43, 44, 27, 28, 29,
        45, 46, 47, 30, 31, 32
    };

    // Check
    ASSERT_TRUE (dofGlobalIdTarget == dofGlobalIndexesTest);
}

TEST (DOFHandlerTest, IncludeRBE2Case)
{
    // Input
    Desk_RBe2Surface model;
    auto dbServiceFactory = model.GetModel ();

    // Test data
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    const std::vector<std::size_t> indexes {0, 1, 2, 3, 4, 5, 6, 7};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Elastic, indexes);
    Subcase subcase;
    // subcase.m_spc = 1;
    subcase.AddParameter({"SPC","1"});

    dofhandler.Compute (dbServiceFactory, subcase);
    DofSet DOFs = getAllNodeDofs (); 
    std::vector<int> dofGlobalIndexesTest;
    dofhandler.GetGlobalIndex (indexes, DOFs, _OUT dofGlobalIndexesTest);
    
    // Target data
    const std::vector<int> dofGlobalIdTarget
    {
        33, 34, 35, 0, 1, 2,
        3,   4, 36, 5, 6, 7,
        37, 38,  8,  9, 10, 11,
        12, 13, 14, 15, 16, 17,
        18, 19, 20, 21, 22, 23,
        39, 40, 41, 24, 25, 26,
        42, 43, 44, 27, 28, 29,
        45, 46, 47, 30, 31, 32
    };
    // Check
    ASSERT_TRUE (dofGlobalIdTarget == dofGlobalIndexesTest);
}

TEST (DOFHandlerTest, ThermalLinkCase)
{
    Link_TwoEle model;
    auto dbServiceFactory = model.GetModel ();

    // Test data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTest;
    auto nodeIds = dbServiceFactory -> get<INodeService>()->GetAllId();
    std::vector<std::size_t> indexes {0, 1, 2};
    DOFHandler dofhandler (nodeIds, Field_Types::FIELD_Thermal, indexes);
    Subcase subcase;
    subcase.AddParameter({"SPC","2"});
    // subcase.m_spc = 2;

    dofhandler.MarkDOFType (dbServiceFactory, subcase, DOFFlagTest);

    // Target data
    std::vector<SG::DataStructure::FEM::DOFTypes> DOFFlagTarget{DOFTypes::DOFTYPE_Constraint, DOFTypes::DOFTYPE_Constraint, DOFTypes::DOFTYPE_Free};
    const std::size_t activatedDofCountTarget = 1; 

    // Check
    ASSERT_TRUE (DOFFlagTarget == DOFFlagTest);
    ASSERT_TRUE (activatedDofCountTarget == dofhandler.ComputeSparseMatrixSize ());
    
    // DOF global index test
    std::vector<int> dofGlobalIndexesTest;
    dofhandler.Sort (DOFFlagTest);
    dofhandler.GetGlobalIndex (indexes, {DOFDirections::DOF_Ux}, dofGlobalIndexesTest);
    std::vector<int> dofGlobalIndexesTarget {1, 2, 0};

    ASSERT_TRUE (dofGlobalIndexesTest == dofGlobalIndexesTarget);
}

}; // end namespace FEMSolver
SG_NAMESPACE_CLOSE